#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##-- G12 -- S10 ------------------------------------------------------------##
__all__ = []

from .. import comparecards as cmp_cards
from .. import formlib as layout
from .. import pilelib as stack
from .. import quickplayscore as quickplay
from ..forms import (fortythieves as FortyThievesLayout,
                     klondike as KlondikeLayout,)
from ..gamelib import info as gi, state, game
from ..hint import CautiousDefaultHint
from ..packlib import info as cs, place
from ..utillib.misc import kwdefault

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper


class DerKatzenschwanzHint(CautiousDefaultHint):

    def score_move_pile(self, from_stack, to_stack, pile, rpile):
        """
        score_move_pile(from_stack:Stack, to_stack:Stack, pile:seq(Card ...),
          rpile:seq(Card ...)) -> None

        Score moving a pile from stack to to stack.

        Augment **from_stack** builds **to_stack** prefer not clear stack.
        """
        if not rpile:
            self._score = 0
        else:
            super(DerKatzenschwanzHint, self).score_move_pile(from_stack,
                                                          to_stack, pile, rpile)


class SalicLaw_Hint(CautiousDefaultHint):

    def score_drop_card(self, from_stack, to_stack, ncards):
        """
        score_drop_card(from_stack:obj, to_stack:obj, ncards:int) -> None

        Score dropping a pile of ncards from to stack to from_stack.

        :param Stack to_stack: card destination
        :param integer ncards: num cards dropping
        """
        self._score += len(from_stack.cards)


class SalicLawTalon(stack.DealRowTalon):
    """
    Deal 1 card on 1 pile of _row_. Each next_row rank moves deal next pile.
    """

    def __init__(self, x, y, game, next_row, offset=(0, 0), **cap):
        """
        __init__(x:int, y:int, game:obj[, offset:tup=(0, 0), max_rounds:int=1,
          num_deal:int=1, *capability* {}]) -> None

        :cvar integer max_rounds: number of times through pile.
        :cvar integer num_deal: number of cards each pile recieves at once.
        :cvar object images: pile's base and shadow image
        :cvar object items: pile's base and shadow item
        :cvar object texts: pile's base and shadow item

        :param integer x: left x-coordinate.
        :param integer y: top y-coordinate.
        :param object game: current Game.
        :keyword tuple offset: offset from left top per card on pile.
        :keyword integer max_rounds: number of times through pile.
        :keyword integer num_deal: number of cards each pile recieves at once.

        seealso::
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        self._next_row = next_row
        super(SalicLawTalon, self).__init__(x, y, game, offset, **cap)

    @property
    def _piles(self):
        """
        _piles -> tup

        :return: deal Game.s.rows
        :rtype: tuple
        """
        ri = sum(1 for r in self.game.s['rows'] if r.cards)
        if not self.TOPCARD['rank'] == self._next_row:
            ri -= 1
        return [self.game.s['rows'][ri]]


class SalicLawTalon2(SalicLawTalon):
    """
    Deal 1 card on 1 pile of _row_. Each next_row rank moves deal next pile.
    Finish ACE on _foundation_.
    """

    @property
    def _piles(self):
        """
        _piles -> tup

        :return: deal Game.s.rows
        :rtype: tuple
        """
        if self.TOPCARD['rank'] == cs.ACE:
            return [s for s in self.game.s['foundations'] if not s.cards][:1]
        else:
            return super(SalicLawTalon2, self)._piles()


class StepUp_Talon(stack.WasteTalon):
    """
    Deal 1 card on _waste_ when _reserve_ has cards.
    """

    def can_deal_cards(self):
        """
        can_deal_cards() -> bool

        Check by Game.talon_deal() if pile can deal more cards.

        :return: deal more cards?
        :rtype: True | False
        """
        if not super(StepUp_Talon, self).can_deal_cards():
            return False
        return all(bool(r.cards) for r in self.game.s['reserves'])


class SalicLaw_Foundation(stack.FromRowStackBuildMethod, stack.RK_Foundation):
    """
    Build up in rank alone from _row_ on pile with _row_ id + 8 has cards.
    """

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack:obj, cards:tup) -> bool

        Check parent capable then neighbor _row_ gap.

        :param object from_stack: pile playing cards.
        :param tuple cards: cards playing on pile.
        :return: pile can build with cards from played from_stack?
        :rtype: boolean

        seealso:
          Method pysollib.stackcaps.builds for the *capability* check.
        """
        if not super(SalicLaw_Foundation, self).cardsBuild(from_stack, cards):
            return False
        return len(self.game.allstacks[self.id + 8].cards) > 0


class LaggardLady_Foundation(stack.RK_Foundation):
    """
    Build up in rank alone from _row_ on pile with _row_ id % 8 has cards.
    """

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack:obj, cards:tup) -> bool

        Check parent capable then neighbor _row_ cards.

        :param object from_stack: pile playing cards.
        :param tuple cards: cards playing on pile.
        :return: pile can build with cards from played from_stack?
        :rtype: boolean

        seealso:
          Method pysollib.stackcaps.builds for the *capability* check.
        """
        if not super(LaggardLady_Foundation, self).cardsBuild(from_stack,
                                                              cards):
            return False
        if cards[0]['rank'] == self.cap['base_rank']:
            return bool(self.game.s['rows'][self.id % 8].cards)
        return True


class Glencoe_Foundation(stack.RK_Foundation):
    """
    Build up in rank alone from _row_ on pile with _row_ id % 8 has cards.
    Base is same suit as _row_ id % 8 base.
    """

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack:obj, cards:tup) -> bool

        Check parent capable then neighbor _row_ cards and has same suit as
        its base.

        :param object from_stack: pile playing cards.
        :param tuple cards: cards playing on pile.
        :return: pile can build with cards from played from_stack?
        :rtype: boolean

        seealso:
          Method pysollib.stackcaps.builds for the *capability* check.
        """
        if not super(Glencoe_Foundation, self).cardsBuild(from_stack, cards):
            return False
        if cards[0]['rank'] in (cs.FIVE, cs.SIX):
            row = self.game.s['rows'][self.id % 8]
            return row.cards and cmp_cards.isSameSuit(cards + [row.BASECARD])
        return True


class StepUp_Foundation(stack.Vary_SS_Foundation):
    """
    Build up in rank by same suit from base from reserve or any when _reserve_
    gap.
    """

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack:obj, cards:tup) -> bool

        Check parent capable then from _reserve_ or any when _reserve_ gap.

        :param object from_stack: pile playing cards.
        :param tuple cards: cards playing on pile.
        :return: pile can build with cards from played from_stack?
        :rtype: boolean

        seealso:
          Method pysollib.stackcaps.builds for the *capability* check.
        """
        if not super(StepUp_Foundation, self).cardsBuild(from_stack, cards):
            return False
        return (from_stack in self.game.s['reserves'] or
                any(not r.cards for r in self.game.s['reserves']))


class FaerieQueen_RowStack(stack.EmptyTalonBuildMethod, stack.RK_RowStack):
    """
    Build up in rank alone or any on base card. Play seq.
    """

    def _sequence(self, cards):
        """
        _sequence(cards:obj) -> bool

        Are cards are in rank order.

        :param sequence cards: cards from sending pile
        :return: right sequence?
        :rtype: boolean
        """
        return (len(self.cards) == 1 or
                super(FaerieQueen_RowStack).isSequence(cards))


class Intrigue_RowStack(stack.EmptyTalonBuildMethod, stack.ReserveStack):
    """
    Build any 1 card. Play top.
    """
    pass


class StepUp_RowStack(stack.FromWasteBuildMethod, stack.AC_RowStack):
    """
    Build up in rank by alt color from _waste_. Play seq.
    """
    pass


class DerKatzenschwanz(game.Game):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal all cards with KING start pile.
      Build down in rank by alt color. Play seq. Base none.

    _reserve_
      Pile 8 N horz. Build any 1 card. Play top.

    _foundation_
      Pile 8 over 2 col E. Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=GAP)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=141, name='Catʼs Tail', game_type=(GT.FREECELL |
                    GT.OPEN), decks=2, skill_level=SL.MOSTLY_SKILL,
                    altnames=('Der Katzenschwanz',), version='3.20')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = layout.CatsTailLayout
    _talon_ = stack.InitialDealTalon
    _foundation_ = stack.SS_Foundation
    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.GAP)
    _reserve_ = stack.ReserveStack
    _hint_ = DerKatzenschwanzHint

    def _create_game(self, **kw):
        kwdefault(kw, rows=9, reserves=8)
        l, s = super(DerKatzenschwanz, self)._create_game(**kw), self.s
        self.table_size = l.size
        playcards = 4 * l.YS / l.YOFFSET
        offset = ((0,) * playcards + (l.XOFFSET,) * (l.NCARDS - playcards),
                  (l.YOFFSET,) * playcards + (0,) * (l.NCARDS - playcards),)
        for r in l.s['reserves']:
            s['reserves'].append(self._reserve_(r.x, r.y, game=self))
        for r in l.s['rows']:
            s['rows'].append(self._row_(r.x, r.y, game=self, offset=offset))
        for r in l.s['foundations']:
            s['foundations'].append(self._foundation_(r.x, r.y, game=self,
                                                   suit=r.suit))
        s['talon'] = self._talon_(l.s['talon'].x, l.s['talon'].y, game=self)
        l.defaultAll()
        return l

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows] all. next before KING.

        .. \_start([]) -> None
        """
        i = 0
        while self.s['talon'].cards:
            if self.s['talon'].TOPCARD['rank'] == cs.KING and self.s['rows'][i].cards:
                i += 1
            self.s['talon'].dealRow(rows=[self.s['rows'][i]], frames=4)

    def _closest_stack(self, cx, cy, stacks, dragstack):
        """
        Compare stack coords for closest stacks to current `cx`, `cy` coords.
        Overides for stacks with both vertical and horizontal or no offset.

        :Parameter:
          cx : int

          cy : int

          stacks : list

          dragstack : list

        :returns: closest stack to coords.
        """
        closest, cdist = None, 999999999
        for stack in stacks:
            if stack.cards and stack is not dragstack:
                coords = (stack.TOPCARD.x, stack.TOPCARD.y,)
            else:
                coords = (stack.x, stack.y,)
            dist = sum((c - cx) ** 2 for c in coords)
            if dist < cdist:
                closest, cdist = stack, dist
        return closest


class DieSchlange(DerKatzenschwanz):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal all cards with KING start pile. Build
      down in rank by alt color. Play top, seq of possible moves play as one.
      Base none.

    _reserve_
      Pile 7 N horz. Build any 1 card. Play top.

    _foundation_
      Pile 8 over 2 col E. Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.SuperMoveAC_RowStack (base_rank=GAP)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=142, name='Snake', game_type=(GT.FREECELL | GT.OPEN),
                    decks=2, skill_level=SL.MOSTLY_SKILL,
                    altnames=('Die Schlange',), version='3.20')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _row_ = Wrap(stack.SuperMoveAC_RowStack, base_rank=cs.GAP)

    def _create_game(self, **kw):
        kwdefault(kw, rows=9, reserves=7)
        return super(DieSchlange, self)._create_game(**kw)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows] all. next before KING. row or drop 1st.

        .. \_start([]) -> None
        """
        i = 0
        while self.s['talon'].cards:
            if self.s['talon'].TOPCARD['rank'] == cs.KING and self.s['rows'][i].cards:
                i += 1
            self.s['talon'].deal_row_or_drop(stacks=[self.s['rows'][i]])


class Retinue(DieSchlange):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal all cards with KING start pile. Build
      down in rank by alt color. Play top, seq of possible moves play as one.
      Base none.

    _reserve_
      Pile 8 N horz. Build any 1 card. Play top.

    _foundation_
      Pile 8 over 2 col E. Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.SuperMoveAC_RowStack (base_rank=GAP)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=286, name='Retinue', game_type=(GT.FREECELL |
                    GT.OPEN | GT.ORIGINAL), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='0.80fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    def _create_game(self, **kw):
        kwdefault(kw, rows=9, reserves=8)
        return super(DieSchlange, self)._create_game(**kw)


class Kings(DerKatzenschwanz):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 8 horz S _reserve_. Init deal KING 1st then all cards with KING
      start pile. Build down in rank by alt color. Play seq. Base none.

    _reserve_
      Pile 8 N horz. Build any 1 card. Play top.

    _foundation_
      Pile 8 over 2 col E. Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=GAP)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=279, name='Kings', game_type=(GT.FREECELL | GT.OPEN |
                    GT.POPULAR | GT.KDE), decks=2, version='0.80fc',
                    skill_level=SL.MOSTLY_SKILL)
    __author__ = 'Skomoroh'
    __version__ = 7.70

    def _create_game(self, **kw):
        kw.setdefault('rows', 8)
        return super(Kings, self)._create_game(**kw)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return single KING on top for _row_ deal.
        """
        return place.MoveToTop(cards, place.AllKings, ncards=1)


class Kentish(DerKatzenschwanz):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 8 horz N. Init deal all cards with ACE end pile. Build down in rank
      alone. Play seq.

    _foundation_
      Pile 8 over 2 col E. Build up in rank alone. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.RK_Foundation
    :cvar Stack _row_: stack.RK_RowStack
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=766, name='Kentish', game_type=(GT.TWO_DECK |
                    GT.OPEN | GT.ORIGINAL), decks=2,
                    skill_level=SL.MOSTLY_SKILL, version='1.00fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundation_ = stack.RK_Foundation
    _row_ = stack.RK_RowStack

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, reserves=0)
        return super(Kentish, self)._create_game(**kw)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return single ACE on bottom for _row_ play.
        """
        return place.MoveToBottom(cards, place.AllAces, ncards=1)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows] all. next after ACE

        .. \_start([]) -> None
        """
        i = 0
        while self.s['talon'].cards:
            rank = self.s['talon'].TOPCARD['rank']
            self.s['talon'].dealRow(rows=[self.s['rows'][i]], frames=4)
            if rank == cs.ACE and self.s['rows'][i].cards:
                i += 1


class Deep(DerKatzenschwanz):
    """
    Finish cards on _foundation_ within a turn.

    _row_
      Pile 8 horz S _reserve_. Init deal 13 open cards. Build down in rank by
      alt color. Play seq.

    _reserve_
      Pile 8 N horz. Build any 1 card. Play top.

    _foundation_
      Pile 8 over 2 col E. Build up in rank by same suit. Play top.
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation
    :cvar Stack _row_: stack.AC_RowStack (base_rank=ANY)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=442, name='Deep', game_type=(GT.FREECELL | GT.OPEN
                    | GT.ORIGINAL), decks=2, version='0.92fc',
                    skill_level=SL.MOSTLY_SKILL)
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _row_ = Wrap(stack.AC_RowStack, base_rank=cs.ANY)

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, reserves=8)
        return super(Deep, self)._create_game(**kw)

    def _start(self, rows=13):
        """
        Deal initial cards for new game.
          - s[rows] 13 ea up.

        .. \_start([rows=13]) -> None
        """
        for i in range(rows - 1):
            self.s['talon'].dealRow(frames=0)
        self.s['talon'].dealRow()


class FaerieQueen(DerKatzenschwanz):
    """
    Finish cards except KING on _foundation_ within a turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.klondike.KlondikeLayout
        - row [8 horz S foundation, vert offset]
        - talon [1 NW, no offset]
        - foundation [8 horz N, no offset]
    _row_
      Init deal a KING. Build down in rank alone or
      any card on on KING after _talon_ gap . Play top. Base none.

    _talon_
      Deal 1 card on 1 pile of _row_. Each KING moves deal next pile.

    _foundation_
      Build up in rank alone . Play none.
    ------
    :cvar Stack _talon_: SalicLawTalon (next_row=KING)
    :cvar Stack _foundation_: stack.RK_Foundation (max_cards=12,
      max_move=0)
    :cvar Stack _row_: FaerieQueen_RowStack (min_cards=1, max_move=1,
      base_rank=GAP)
    :cvar Stack _reserve_: None
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=611, name='Faerie Queen', game_type=GT.TWO_DECK,
                    decks=2, skill_level=SL.BALANCED,
                    version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = KlondikeLayout.KlondikeLayout
    _talon_ = Wrap(SalicLawTalon, next_row=cs.KING)
    _foundations_ = (Wrap(stack.RK_Foundation, max_cards=12,
                                  max_move=0),)
    _row_ = Wrap(FaerieQueen_RowStack, min_cards=1, max_move=1,
                         base_rank=cs.GAP)
    _reserve_ = None

    def _create_game(self, **kw):
        kwdefault(kw, rows=8, reserves=0, texts=True)
        return super(FaerieQueen, self)._create_game(**kw)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return single KING on top for _row_ deal.
        """
        return place.MoveToTop(cards, place.AllKings, ncards=1)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[rows][:1] 1 ea.

        .. \_start([]) -> None
        """
        self.s['talon'].dealRow(self.s['rows'][:1])  # deal King

    @property
    def is_complete(self):
        if self.s['talon'].cards:
            return False
        return all(len(s.cards) == s.cap['max_cards']
                       for s in self.s['foundations'])

    _quickplay_ = quickplay.RowStackLen


class SalicLaw(FaerieQueen):
    """
    Finish cards except KING on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal a KING. Build any 1 card on KING.
      Play top. Base none.

    _talon_
      Pile 1. Deal 1 card on 1 pile of _row_. Each KING moves deal next pile.
      Finish ACE on _foundation_.

    _foundation_
      Pile 16 over 2 row N. Init deal base QUEEN N. S Build up in rank alone
      from _row_ on pile with neighbor below has cards. Play none.

    seealso::
      http://en.wikipedia.org/wiki/Salic_Law_%28solitaire%29
    ------
    :cvar Stack _talon_: SalicLawTalon2 (next_row=KING)
    :cvar Stack _foundation_: stack.AbstractFoundation (max_cards=1,
      base_rank=QUEEN, max_move=0), SalicLaw_Foundation (max_cards=11,
      max_move=0)
    :cvar Stack _row_: stack.ReserveStack (min_cards=1, max_cards=2,
      base_rank=gap)
    :cvar Stack _reserve_: None
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=299, name='Salic Law', game_type=GT.TWO_DECK,
                    decks=2, skill_level=SL.MOSTLY_LUCK,
                    version='0.80fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _hint_ = SalicLaw_Hint

    _talon_ = Wrap(SalicLawTalon2, next_row=cs.KING)
    _foundations_ = (Wrap(stack.AbstractFoundation, max_cards=1,
                                  base_rank=cs.QUEEN, max_move=0),
                     Wrap(SalicLaw_Foundation, max_cards=11,
                                  max_move=0),)
    _row_ = Wrap(stack.ReserveStack, min_cards=1, max_cards=2,
                         base_rank=cs.GAP)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return QUEEN and King of suit on top by rank, suit, deck for
        _foundation_ deal.
        """
        cards = super(SalicLaw, self)._pack_place(cards)
        return place.MoveToTop(cards, place.AllQueens)

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[foundations][:8] 1 base.
          - s[rows][:1] 1 ea.

        .. \_start([]) -> None
        """
        self.s['talon'].dealRow(self.s['foundations'][:8])  # deal Queens
        super(SalicLaw, self)._start(**kw)


class Intrigue(FaerieQueen):
    """
    Finish cards except QUEEN on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal a KING. Build down in rank alone or
      any card on on QUEEN after _talon_ gap . Play top. Base none.

    _talon_
      Pile 1. Deal 1 card on 1 pile of _row_. Each QUEEN moves deal next pile.

    _foundation_
      Pile 16 over 2 row N. Build in rank alone: N up from base SIX and S down
      from base FIVE wrap. Play top.

    seealso::
      http://en.wikipedia.org/wiki/Intrigue_%28solitaire%29
    ------
    :cvar Stack _talon_: SalicLawTalon (next_row=QUEEN)
    :cvar Stack _foundation_: stack.RK_Foundation (base_rank=SIX,
      max_cards=6), stack.RK_Foundation (base_rank=FIVE, max_cards=6,
      dir=-1, mod=13)
    :cvar Stack _row_: Intrigue_RowStack (min_cards=1, max_move=1,
      base_rank=GAP)
    :cvar Stack _reserve_: None
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=523, name='Intrigue', game_type=GT.TWO_DECK, decks=2,
                    skill_level=SL.BALANCED, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = Wrap(SalicLawTalon, next_row=cs.QUEEN)
    _foundations_ = (Wrap(stack.RK_Foundation, base_rank=cs.SIX,
                                  max_cards=6),
                     Wrap(stack.RK_Foundation, base_rank=cs.FIVE,
                                  max_cards=6, dir=-1, mod=13),)
    _row_ = Wrap(Intrigue_RowStack, min_cards=1, max_cards=2,
                         base_rank=cs.GAP)

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return single QUEEN on top for _row_ deal.
        """
        return place.MoveToTop(cards, place.AllQueens, ncards=1)


class Glencoe(Intrigue):
    """
    Finish cards except QUEEN on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal a KING. Build down in rank alone or
      any card on on QUEEN after _talon_ gap . Play top. Base none.

    _talon_
      Pile 1. Deal 1 card on 1 pile of _row_. Each QUEEN moves deal next pile.

    _foundation_
      Pile 16 over 2 row N. Build in rank alone after S neighbor _row_ has
      cards: N up from base SIX of same suit as S neighbor _row_ base and S
      down from base FIVE of same suit as S neighbor _row_ base wrap. Play
      top.

    seealso::
      http://en.wikipedia.org/wiki/Intrigue_%28solitaire%29
    ------
    :cvar Stack _talon_: SalicLawTalon (next_row=QUEEN)
    :cvar Stack _foundation_: Glencoe_Foundation (base_rank=SIX, max_cards=6),
      Glencoe_Foundation (base_rank=FIVE, max_cards=6, dir=-1, mod=13)
    :cvar Stack _row_: Intrigue_RowStack (min_cards=1, max_move=1,
      base_rank=GAP)
    :cvar Stack _reserve_: None
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=612, name='Glencoe', game_type=GT.TWO_DECK, decks=2,
                    skill_level=SL.BALANCED, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundations_ = (Wrap(Glencoe_Foundation, base_rank=cs.SIX,
                                  max_cards=6),
                     Wrap(Glencoe_Foundation, base_rank=cs.FIVE,
                                  max_cards=6, dir=-1, mod=13),)


class LaggardLady(Intrigue):
    """
    Finish cards except QUEEN on _foundation_ within a turn.

    _row_
      Pile 9 horz S _reserve_. Init deal a KING. Build down in rank alone or
      any card on on QUEEN after _talon_ gap . Play top. Base none.

    _talon_
      Pile 1. Deal 1 card on 1 pile of _row_. Each QUEEN moves deal next pile.

    _foundation_
      Pile 16 over 2 row N. Build in rank alone after neighbor _row_ S has
      cards: N up from base SIX and S down from base FIVE wrap. Play top.

    seealso::
      http://en.wikipedia.org/wiki/Intrigue_%28solitaire%29
    ------
    :cvar Stack _talon_: SalicLawTalon (next_row=QUEEN)
    :cvar Stack _foundation_: LaggardLady_Foundation (base_rank=SIX,
      max_cards=6), LaggardLady_Foundation (base_rank=FIVE, max_cards=6,
      dir=-1, mod=13)
    :cvar Stack _row_: Intrigue_RowStack (min_cards=1, max_move=1,
      base_rank=GAP)
    :cvar Stack _reserve_: None
    :cvar Hint _hint_: DerKatzenschwanzHint
    """
    __info__ = dict(id=616, name='Laggard Lady', game_type=GT.TWO_DECK,
                    decks=2, skill_level=SL.BALANCED,
                    version='0.93')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _foundations_ = (Wrap(LaggardLady_Foundation, base_rank=cs.SIX,
                          max_cards=6),
                     Wrap(LaggardLady_Foundation, base_rank=cs.FIVE,
                          max_cards=6, dir=-1, mod=13),)


class StepUp(game.Game):
    """
    Finish cards on _foundation_ within a turn.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.fortythieves.FortyThievesLayout
        - row [9 horz S reserve, vert offset]
        - reserve [13 horz S foundation, no offset]
        - talon [1 SW, no offset]
        - waste [1 E, horz offset]
        - foundation [8 horz NE, no offset]

    _row_
      Init deal 1 card. Build down in rank by alt
      color wrap from _waste_. Play top.

    _reserve_
      Init deal 1 card. Build any 1 card.
      Play top.

    _talon_
      Deal 1 card on _waste_.

    _waste_
      Build none. Play top.

    _foundation_
      Init deal 1 base card. Build in rank by same suit from
      base wrap. Play top.

    ------
    :cvar Stack _talon_: StepUp_Talon
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: StepUp_Foundation (mod=13, base_rank=ANY)
    :cvar Stack _row_: StepUp_RowStack (max_move=1, mod=13)
    :cvar Stack _reserve_: stack.ReserveStack
    :cvar Hint _hint_: hint.CautiousDefaultHint
    """
    __info__ = dict(id=624, name='Step-Up', game_type=GT.TWO_DECK, decks=2,
                    skill_level=SL.BALANCED, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = FortyThievesLayout.FortyThievesLayout
    _talon_ = StepUp_Talon
    _waste_ = stack.WasteStack
    _foundation_ = StepUp_Foundation
    _row_ = Wrap(StepUp_RowStack, max_move=1, mod=13)
    _reserve_ = stack.ReserveStack
    _hint_ = CautiousDefaultHint

    def _create_game(self, **kw):
        kwdefault(kw, rows=9, reserves=13, texts=True)
        l, s = super(StepUp, self)._create_game(**kw), self.s
        self.game.texts['info'] = l.create_info_text(s['foundations'][0], 'sw')
        return l

    def _start(self, **kw):
        """
        Deal initial cards for new game.
          - s[foundations] 1 base.
          - s[reserves] 1 ea.
          - s[rows] 1 ea.

        .. \_start([]) -> None
        """
        base_rank = self.s['talon'].TOPCARD['rank']
        self.s['talon'].dealBaseCards(ncards=1, saveinfo=False)
        self._save_stack_caps(self.s['foundations'], base_rank=base_rank)
        self.s['talon'].dealRow(rows=self.s['reserves'], frames=0)
        self.s['talon'].dealRow()

    @state.not_state('is_preview')
    def _update_text(self):
        if not self.texts['info']:
            return
        base_rank = self.s['foundation'].cap['base_rank']
        t = '' if base_rank == cs.ANY else self.RANKS[base_rank]
        self.texts['info'].config(text=t)


PROVIDES = [DerKatzenschwanz, DieSchlange, Kings, Retinue, SalicLaw, Deep,
            Intrigue, FaerieQueen, Glencoe, LaggardLady, StepUp, Kentish]